Amplify ordenar resultados

Descripcion

Como obtener los resultados de una API de amplify (AppSync/GraphQL) de manera ordenada (Ascendente o Descendente).

Usaremos ESTE EJEMPLO como código base

Descripcion

Pimero editamos el schema.graphql (amplify/backend/api/todoapptest/schema.graphql) añadiendo lo siguiente:

type: String! @index(name: "todosByDate", queryField: "todosByDate", sortKeyFields: ["timestamp"])
timestamp: String!

Hacemos un push de amplify:

amplify push

Se nos preguntara si queremos actualizar la API de GraphQL y regenerar las consultas, le decimos que si.

Esta operación puede tardar varios minutos, una vez terminado nos indica que el despliegue se ha realizado satisfactoriamente:

Antes de poner hacer las consultas, tenemos que modificar la manera en la que guardamos los datos para añadir los campos type y timestamp:

Ahora para hacer las consultas lo hacemos de la siguiente manera:

Antes usabamos la funcion ListTodos de la API, pero ahora usamos TodosByDate que esta funcion se autogenera a partir del indice que hemos indicado en el schema.

La firma de la función es la siguiente:

El primer parámetro es type, el segundo timestamp, el tercero sortDirection, el cuarto filter y el quinto limit

Por eso hay algunos undefined por el medio, porque esos parámetros no nos interesa pasarles ningun valor.

Cambios manuales

Los cambios que se realizan despues de hacer el amplify push son los siguientes:

DynamoDB

En DynamoDB se añade un index con los parámetros que hemos indicado en el schema:

AppSync

En AppSync se modifica el schema, añadiendo el siguiente tipo:

Y tambien en la query:

El schema completo antes de hacer los cambios era el siguiente:

input CreateTodoInput {
	id: ID
	name: String!
	description: String
}

input DeleteTodoInput {
	id: ID!
}

enum ModelAttributeTypes {
	binary
	binarySet
	bool
	list
	map
	number
	numberSet
	string
	stringSet
	_null
}

input ModelBooleanInput {
	ne: Boolean
	eq: Boolean
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
}

input ModelFloatInput {
	ne: Float
	eq: Float
	le: Float
	lt: Float
	ge: Float
	gt: Float
	between: [Float]
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
}

input ModelIDInput {
	ne: ID
	eq: ID
	le: ID
	lt: ID
	ge: ID
	gt: ID
	contains: ID
	notContains: ID
	between: [ID]
	beginsWith: ID
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
	size: ModelSizeInput
}

input ModelIntInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
}

input ModelSizeInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
}

enum ModelSortDirection {
	ASC
	DESC
}

input ModelStringInput {
	ne: String
	eq: String
	le: String
	lt: String
	ge: String
	gt: String
	contains: String
	notContains: String
	between: [String]
	beginsWith: String
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
	size: ModelSizeInput
}

input ModelSubscriptionBooleanInput {
	ne: Boolean
	eq: Boolean
}

input ModelSubscriptionFloatInput {
	ne: Float
	eq: Float
	le: Float
	lt: Float
	ge: Float
	gt: Float
	between: [Float]
	in: [Float]
	notIn: [Float]
}

input ModelSubscriptionIDInput {
	ne: ID
	eq: ID
	le: ID
	lt: ID
	ge: ID
	gt: ID
	contains: ID
	notContains: ID
	between: [ID]
	beginsWith: ID
	in: [ID]
	notIn: [ID]
}

input ModelSubscriptionIntInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
	in: [Int]
	notIn: [Int]
}

input ModelSubscriptionStringInput {
	ne: String
	eq: String
	le: String
	lt: String
	ge: String
	gt: String
	contains: String
	notContains: String
	between: [String]
	beginsWith: String
	in: [String]
	notIn: [String]
}

input ModelSubscriptionTodoFilterInput {
	id: ModelSubscriptionIDInput
	name: ModelSubscriptionStringInput
	description: ModelSubscriptionStringInput
	and: [ModelSubscriptionTodoFilterInput]
	or: [ModelSubscriptionTodoFilterInput]
}

input ModelTodoConditionInput {
	name: ModelStringInput
	description: ModelStringInput
	and: [ModelTodoConditionInput]
	or: [ModelTodoConditionInput]
	not: ModelTodoConditionInput
}

type ModelTodoConnection {
	items: [Todo]!
	nextToken: String
}

input ModelTodoFilterInput {
	id: ModelIDInput
	name: ModelStringInput
	description: ModelStringInput
	and: [ModelTodoFilterInput]
	or: [ModelTodoFilterInput]
	not: ModelTodoFilterInput
}

type Todo {
	id: ID!
	name: String!
	description: String
	createdAt: AWSDateTime!
	updatedAt: AWSDateTime!
}

input UpdateTodoInput {
	id: ID!
	name: String
	description: String
}

type Mutation {
	createTodo(input: CreateTodoInput!, condition: ModelTodoConditionInput): Todo
	updateTodo(input: UpdateTodoInput!, condition: ModelTodoConditionInput): Todo
	deleteTodo(input: DeleteTodoInput!, condition: ModelTodoConditionInput): Todo
}

type Query {
	getTodo(id: ID!): Todo
	listTodos(filter: ModelTodoFilterInput, limit: Int, nextToken: String): ModelTodoConnection
}

type Subscription {
	onCreateTodo(filter: ModelSubscriptionTodoFilterInput): Todo
		@aws_subscribe(mutations: ["createTodo"])
	onUpdateTodo(filter: ModelSubscriptionTodoFilterInput): Todo
		@aws_subscribe(mutations: ["updateTodo"])
	onDeleteTodo(filter: ModelSubscriptionTodoFilterInput): Todo
		@aws_subscribe(mutations: ["deleteTodo"])
}

Y despues de hacer los cambios es el siguiente:

input CreateTodoInput {
	id: ID
	name: String!
	description: String
	type: String!
	timestamp: String!
}

input DeleteTodoInput {
	id: ID!
}

enum ModelAttributeTypes {
	binary
	binarySet
	bool
	list
	map
	number
	numberSet
	string
	stringSet
	_null
}

input ModelBooleanInput {
	ne: Boolean
	eq: Boolean
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
}

input ModelFloatInput {
	ne: Float
	eq: Float
	le: Float
	lt: Float
	ge: Float
	gt: Float
	between: [Float]
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
}

input ModelIDInput {
	ne: ID
	eq: ID
	le: ID
	lt: ID
	ge: ID
	gt: ID
	contains: ID
	notContains: ID
	between: [ID]
	beginsWith: ID
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
	size: ModelSizeInput
}

input ModelIntInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
}

input ModelSizeInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
}

enum ModelSortDirection {
	ASC
	DESC
}

input ModelStringInput {
	ne: String
	eq: String
	le: String
	lt: String
	ge: String
	gt: String
	contains: String
	notContains: String
	between: [String]
	beginsWith: String
	attributeExists: Boolean
	attributeType: ModelAttributeTypes
	size: ModelSizeInput
}

input ModelStringKeyConditionInput {
	eq: String
	le: String
	lt: String
	ge: String
	gt: String
	between: [String]
	beginsWith: String
}

input ModelSubscriptionBooleanInput {
	ne: Boolean
	eq: Boolean
}

input ModelSubscriptionFloatInput {
	ne: Float
	eq: Float
	le: Float
	lt: Float
	ge: Float
	gt: Float
	between: [Float]
	in: [Float]
	notIn: [Float]
}

input ModelSubscriptionIDInput {
	ne: ID
	eq: ID
	le: ID
	lt: ID
	ge: ID
	gt: ID
	contains: ID
	notContains: ID
	between: [ID]
	beginsWith: ID
	in: [ID]
	notIn: [ID]
}

input ModelSubscriptionIntInput {
	ne: Int
	eq: Int
	le: Int
	lt: Int
	ge: Int
	gt: Int
	between: [Int]
	in: [Int]
	notIn: [Int]
}

input ModelSubscriptionStringInput {
	ne: String
	eq: String
	le: String
	lt: String
	ge: String
	gt: String
	contains: String
	notContains: String
	between: [String]
	beginsWith: String
	in: [String]
	notIn: [String]
}

input ModelSubscriptionTodoFilterInput {
	id: ModelSubscriptionIDInput
	name: ModelSubscriptionStringInput
	description: ModelSubscriptionStringInput
	type: ModelSubscriptionStringInput
	timestamp: ModelSubscriptionStringInput
	and: [ModelSubscriptionTodoFilterInput]
	or: [ModelSubscriptionTodoFilterInput]
}

input ModelTodoConditionInput {
	name: ModelStringInput
	description: ModelStringInput
	type: ModelStringInput
	timestamp: ModelStringInput
	and: [ModelTodoConditionInput]
	or: [ModelTodoConditionInput]
	not: ModelTodoConditionInput
}

type ModelTodoConnection {
	items: [Todo]!
	nextToken: String
}

input ModelTodoFilterInput {
	id: ModelIDInput
	name: ModelStringInput
	description: ModelStringInput
	type: ModelStringInput
	timestamp: ModelStringInput
	and: [ModelTodoFilterInput]
	or: [ModelTodoFilterInput]
	not: ModelTodoFilterInput
}

type Todo {
	id: ID!
	name: String!
	description: String
	type: String!
	timestamp: String!
	createdAt: AWSDateTime!
	updatedAt: AWSDateTime!
}

input UpdateTodoInput {
	id: ID!
	name: String
	description: String
	type: String
	timestamp: String
}

type Mutation {
	createTodo(input: CreateTodoInput!, condition: ModelTodoConditionInput): Todo
	updateTodo(input: UpdateTodoInput!, condition: ModelTodoConditionInput): Todo
	deleteTodo(input: DeleteTodoInput!, condition: ModelTodoConditionInput): Todo
}

type Query {
	getTodo(id: ID!): Todo
	listTodos(filter: ModelTodoFilterInput, limit: Int, nextToken: String): ModelTodoConnection
	todosByDate(
		type: String!,
		timestamp: ModelStringKeyConditionInput,
		sortDirection: ModelSortDirection,
		filter: ModelTodoFilterInput,
		limit: Int,
		nextToken: String
	): ModelTodoConnection
}

type Subscription {
	onCreateTodo(filter: ModelSubscriptionTodoFilterInput): Todo
		@aws_subscribe(mutations: ["createTodo"])
	onUpdateTodo(filter: ModelSubscriptionTodoFilterInput): Todo
		@aws_subscribe(mutations: ["updateTodo"])
	onDeleteTodo(filter: ModelSubscriptionTodoFilterInput): Todo
		@aws_subscribe(mutations: ["deleteTodo"])
}
Tags

AWS | Amplify | Ordenacion